///////////////////////////////////////////////////////////////////////////////
// File:        Player.hpp
// Author:      671643387@qq.com
// Description: 
///////////////////////////////////////////////////////////////////////////////

#if !defined(SHARED_PLAYER_PLAYER_HPP_)
#define SHARED_PLAYER_PLAYER_HPP_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <cstddef>
#include <deque>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
#include "util/CircleBuffer.hpp"
#include "util/MessageBlock.hpp"

///////////////////////////////////////////////////////////////////////////////
#define PLAYER_RECV_BUFF_SIZE   0x1000

///////////////////////////////////////////////////////////////////////////////
class PlayerManager;
typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;

///////////////////////////////////////////////////////////////////////////////
class Player : public boost::noncopyable
{
public:
    ///////////////////////////////////////////////////////////////////////////
    Player(void);
    ~Player(void);

public:
    ///////////////////////////////////////////////////////////////////////////
    int GetID(void) const;
    std::string GetRemoteIP(void) const;

    void Close(void);

protected:
    ///////////////////////////////////////////////////////////////////////////
    virtual void OnRead(void);
    virtual void OnClose(void);

    ///////////////////////////////////////////////////////////////////////////
    std::size_t RecvLen(void) const;
    std::size_t Recv(char* buf, std::size_t len);
    std::size_t Peek(char* buf, std::size_t len);
    std::size_t Skip(std::size_t len);

    void Send(const char* buf, std::size_t len);

private:
    ///////////////////////////////////////////////////////////////////////////
    friend class PlayerManager;
    void _Init(int id, socket_ptr sock, PlayerManager* mgr);
    void _Close(void);

    void _PostRecv(void);
    void _PostSend(void);
    void _OnRecv(const boost::system::error_code& err, std::size_t bytes_transferred);
    void _OnSend(const boost::system::error_code& err, std::size_t bytes_transferred);

private:
    ///////////////////////////////////////////////////////////////////////////
    enum net_state
    {
        NORMAL,
        CLOSED
    };

    typedef std::deque<MessageBlockPtr>  MessageQueue;

private:
    ///////////////////////////////////////////////////////////////////////////
    int             id_;
    socket_ptr      sock_;
    PlayerManager*  owner_;
    net_state       nstate_;

    char            recvbuf_[0x200];
    CircleBuffer<PLAYER_RECV_BUFF_SIZE> recvcache_;

    std::string     remoteip_;

    bool            sendpending_;
    MessageQueue    messagequeue_;
    boost::mutex    mqlock_;
};

///////////////////////////////////////////////////////////////////////////////
typedef boost::shared_ptr<Player>   PlayerPtr;

#endif //SHARED_PLAYER_PLAYER_HPP_
